/******************************************************************************************************************
 * File:ECSMonitor.java
 * Course: 17655
 * Project: Assignment A3
 * Copyright: Copyright (c) 2009 Carnegie Mellon University
 * Versions:
 *	1.0 March 2009 - Initial rewrite of original assignment 3 (ajl).
 *
 * Description:
 *
 * This class monitors the environmental control systems that control museum temperature and humidity. In addition to
 * monitoring the temperature and humidity, the ECSMonitor also allows a user to set the humidity and temperature
 * ranges to be maintained. If temperatures exceed those limits over/under alarm indicators are triggered.
 *
 * Parameters: IP address of the event manager (on command line). If blank, it is assumed that the event manager is
 * on the local machine.
 *
 * Internal Methods:
 *	static private void Heater(EventManagerInterface ei, boolean ON )
 *	static private void Chiller(EventManagerInterface ei, boolean ON )
 *	static private void Humidifier(EventManagerInterface ei, boolean ON )
 *	static private void Dehumidifier(EventManagerInterface ei, boolean ON )
 *
 ******************************************************************************************************************/
import InstrumentationPackage.*;
import EnumerationPackage.ActionCode;
import EnumerationPackage.EventID;
import EventPackage.*;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.util.*;

class SecMonitor extends Thread
{
	private EventManagerInterface em = null;// Interface object to the event manager
	private String EvtMgrIP = null;			// Event Manager IP address
	private boolean Armed = false;;					// Indicates whether the security monitor is armed 
	private boolean fireDetected = false;	// Indicates whether a fire has been detected 
	private int fireCount = 0;				// Counter for the activation of the sprinkler system
	boolean Registered = true;				// Signifies that this class is registered with an event manager.
	MessageWindow mw = null;				// This is the message window

	private long id = 0;					

	public SecMonitor()
	{
		// event manager is on the local system
		try
		{
			// Here we create an event manager interface object. This assumes
			// that the event manager is on the local machine

			em = new EventManagerInterface();

		}

		catch (Exception e)
		{
			System.out.println("SecMonitor::Error instantiating event manager interface: " + e);
			Registered = false;

		} // catch

	} //Constructor

	public SecMonitor( String EvmIpAddress )
	{
		// event manager is not on the local system

		EvtMgrIP = EvmIpAddress;

		try
		{
			// Here we create an event manager interface object. This assumes
			// that the event manager is NOT on the local machine

			em = new EventManagerInterface( EvtMgrIP );
		}

		catch (Exception e)
		{
			System.out.println("SecMonitor::Error instantiating event manager interface: " + e);
			Registered = false;

		} // catch

	} // Constructor

	public void run()
	{
		Event Evt = null;				// Event object
		EventQueue eq = null;			// Message Queue
		int EvtId = 0;					// User specified event ID
		int	Delay = 1000;				// The loop delay (1 second)
		boolean Done = false;			// Loop termination flag

		if (em != null)
		{
			// Now we create the security status, message panel and indicator

			mw = new MessageWindow("Security Monitoring Console", 0, 0);
			//si = new Indicator ("SEC Test", mw.GetX()+ mw.Width(), 0);

			mw.WriteMessage( "Registered with the event manager." );

			try
			{
				id = em.GetMyId();
				mw.WriteMessage("   Participant id: " + id );
				mw.WriteMessage("   Registration Time: " + em.GetRegistrationTime() );

			} // try

			catch (Exception e)
			{
				System.out.println("Error:: " + e);

			} // catch

			/********************************************************************
			 ** Here we start the main simulation loop
			 *********************************************************************/

			while ( !Done )
			{
				// Here we get our event queue from the event manager

				try
				{
					eq = em.GetEventQueue();

				} // try

				catch( Exception e )
				{
					mw.WriteMessage("Error getting event queue::" + e );

				} // catch

				// If there are messages in the queue, we read through them.
				// We are looking for EventIDs = EventID.SEC or EventID.FIRE 
				// for security arm/disarm events or fire detected/doused events.
				// Note that we get all the messages at once... there is a 1
				// second delay between samples,.. so the assumption is that there should
				// only be a message at most. If there are more, it is the last message
				// that will effect the status security controllers
				// as it would in reality.

				int qlen = eq.GetSize();

				for ( int i = 0; i < qlen; i++ )
				{
					Evt = eq.GetEvent();

					//sends a response based on service maintenance query
					if ( Evt.GetEventId() == EventID.SERV_QUERY.getEventIdNum() ){
						try {
							em.SendEvent(new Event(
									EventID.SERV_REPLY.getEventIdNum(), 
									id+",Security (Sec) Command Console,controls security and fire response"));
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					
					//Security Events
					if ( Evt.GetEventId() == EventID.SEC.getEventIdNum() ) 
					{
						try
						{

							String evtMsg = Evt.GetMessage();

							if (evtMsg.equals(ActionCode.DOOR_BROKEN.getCode())){
								mw.WriteMessage("Door broken!");
							}
							else if (evtMsg.equals(ActionCode.WINDOW_BROKEN.getCode())){
								mw.WriteMessage("Window broken!");
							}
							else if (evtMsg.equals(ActionCode.MOTION_DETECTED.getCode())){
								mw.WriteMessage("Motion detected!");
							}

						} // try

						catch( Exception e )
						{
							mw.WriteMessage("Error reading security event: " + e);

						} // catch

					} // if

					//Fire Events
					if ( Evt.GetEventId() == EventID.FIRE.getEventIdNum() ) 
					{

						String evtMsg = Evt.GetMessage();
						
						if (evtMsg.equals(ActionCode.FIRE_DETECTED.getCode())){
							mw.WriteMessage("FIRE DETECTED! Automatic sprinkler activation in 15 seconds.");
							fireDetected = true;
							fireCount = 15;
						}
						else if (evtMsg.equals(ActionCode.FIRE_DOUSED.getCode())){
							mw.WriteMessage("Fire doused.");
							fireDetected = false;
						}

					} // if

					// If the event ID == 99 then this is a signal that the simulation
					// is to end. At this point, the loop termination flag is set to
					// true and this process unregisters from the event manager.

					else if ( Evt.GetEventId() == EventID.DONE.getEventIdNum() )
					{
						Done = true;

						try
						{
							em.UnRegister();

						} // try

						catch (Exception e)
						{
							mw.WriteMessage("Error unregistering: " + e);

						} // catch

						mw.WriteMessage( "\n\nSimulation Stopped. \n");

						// Get rid of the indicators. The message panel is left for the
						// user to exit so they can see the last message posted.

						//si.dispose();

					} // if

				} // for

				//counts down for automatic sprinkler activation
				if (fireDetected){
					if (fireCount == 1){
						fireCount = 0;
						setSprinkler(true);
					}
					else if(fireCount>0){
						fireCount--;
						mw.WriteMessage("Fire detected. Automatic sprinkler activation in " +
								fireCount +
								" seconds.");
					}
				}
				// This delay slows down the sample rate to Delay milliseconds

				try
				{
					Thread.sleep( Delay );

				} // try

				catch( Exception e )
				{
					System.out.println( "Sleep error:: " + e );

				} // catch

			} // while

		} else {

			System.out.println("Unable to register with the event manager.\n\n" );

		} // if

	} // main

	/***************************************************************************
	 * CONCRETE METHOD:: IsRegistered
	 * Purpose: This method returns the registered status
	 *
	 * Arguments: none
	 *
	 * Returns: boolean true if registered, false if not registered
	 *
	 * Exceptions: None
	 *
	 ***************************************************************************/

	public boolean IsRegistered()
	{
		return( Registered );

	} // SetTemperatureRange

	/***************************************************************************
	 * CONCRETE METHOD:: Halt
	 * Purpose: This method posts an event that stops the environmental control
	 *		   system.
	 *
	 * Arguments: none
	 *
	 * Returns: none
	 *
	 * Exceptions: Posting to event manager exception
	 *
	 ***************************************************************************/

	public void Halt()
	{
		mw.WriteMessage( "***HALT MESSAGE RECEIVED - SHUTTING DOWN SYSTEM***" );

		// Here we create the stop event.

		Event evt;

		evt = new Event( (int) 99, "XXX" );

		// Here we send the event to the event manager.

		try
		{
			em.SendEvent( evt );

		} // try

		catch (Exception e)
		{
			System.out.println("Error sending halt message:: " + e);

		} // catch

	} // Halt

	public void setArmed(boolean armed) {
		try {
			Armed = armed;
			if (armed == true){
				mw.WriteMessage("Security System Armed");
				em.SendEvent(new Event(EventID.SEC_CONTROL.getEventIdNum(), ActionCode.SECURITY_ARMED.getCode()));
			}
			else {
				mw.WriteMessage("Security System Disarmed");
				em.SendEvent(new Event(EventID.SEC_CONTROL.getEventIdNum(), ActionCode.SECURITY_DISARMED.getCode()));
			}
		} catch (Exception e) {
			System.out.println("Error sending security control message:: " + e);
		} 

	}

	public void setSprinkler(boolean ON) {
		try {

			if (ON){
				mw.WriteMessage("Sprinkler Activation");
				fireCount = 0;
				em.SendEvent(new Event(EventID.SPRINK_CONTROL.getEventIdNum(), ActionCode.SPRINKLER_ON.getCode()));
			}
			else {
				mw.WriteMessage("Sprinkler Deactivation");
				em.SendEvent(new Event(EventID.SPRINK_CONTROL.getEventIdNum(), ActionCode.SPRINKLER_OFF.getCode()));
			}
		} catch (Exception e) {
			System.out.println("Error sending security control message:: " + e);
		} 

	}

} // SecMonitor